package utils

import (
	"errors"
	"fmt"
	"log/slog"
	"sort"
	"strconv"
	"time"
)

// CheckSignature 校验签名
// excludeFields 校验签名时，需排除的字段
func CheckSignature(appKey, appSecret string, params map[string]any, excludeFields ...string) error {
	if params == nil {
		err := errors.New("参数为空")
		slog.Error(err.Error())
		return err
	}

	sign, ok := params["sign"]
	if !ok || len(fmt.Sprint(sign)) == 0 {
		err := errors.New("缺少sign参数")
		slog.Error(err.Error())
		return err
	}

	timestamp, ok := params["timestamp"]
	if !ok || len(fmt.Sprint(timestamp)) == 0 {
		err := errors.New("缺少timestamp参数")
		slog.Error(err.Error())
		return err
	}
	timestampObj, err := time.ParseInLocation(TimeFormatDateTimeShort, fmt.Sprint(timestamp), time.Local)
	if err != nil {
		slog.Error(err.Error())
		return errors.New("timestamp格式不正确")
	}

	// 15分钟内有效
	var now = time.Now()
	var diff = timestampObj.Unix() - now.Unix()
	var maxDiff int64 = 15 * 60
	if diff < -maxDiff || diff > maxDiff {
		var errMsg = "timestamp已超时，最大允许范围" + strconv.FormatInt(maxDiff, 10) + "秒，timestamp参数值：" +
			fmt.Sprint(timestamp) + "，当前时间：" + now.Format(TimeFormatDateTimeShort)
		slog.Error(errMsg)
		return errors.New("无效的timestamp")
	}

	reqAppKey := GetValueFromMap(params, "appKey", "appId")
	if reqAppKey == nil || len(fmt.Sprint(reqAppKey)) == 0 {
		err := errors.New("缺少appKey参数")
		slog.Error(err.Error())
		return err
	}
	if reqAppKey != appKey {
		err := errors.New("appKey不正确")
		slog.Error(err.Error())
		return err
	}

	if _, ok := params["appSecret"]; ok {
		err := errors.New("请不要携带appSecret参数")
		slog.Error(err.Error())
		return err
	}

	// 获取除sign之外的参数，生产签名进行校验
	delete(params, "sign")
	var sign2 = GenSignature(params, appSecret, excludeFields...)
	if sign2 != fmt.Sprint(sign) {
		return errors.New("签名校验失败，请检查签名是否正确")
	}

	return nil
}

func GenSignature(params map[string]any, appSecret string, excludeFields ...string) string {
	// 获取除sign之外的参数，生产签名进行校验
	var keys = make([]string, 0)
	for key := range params {
		// sign和excludeFields中的字段不参与签名
		if key == "sign" || (excludeFields != nil && IsInArray(key, excludeFields)) {
			continue
		}
		// 值为空的字段不参与签名
		if params[key] == nil || len(fmt.Sprint(params[key])) == 0 {
			continue
		}
		keys = append(keys, key)
	}
	sort.Slice(keys, func(i, j int) bool {
		return keys[i] < keys[j]
	})

	var origin = ""
	for _, key := range keys {
		if len(origin) > 0 {
			origin += "&"
		}
		origin += key + "=" + fmt.Sprint(params[key])
	}
	origin += "&appSecret=" + appSecret

	signature := SHA1(origin)
	return signature
}
